home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-05-08 | 7.1 KB | 264 lines | [TEXT/MSET] |
- \ 24Jul92 DBH
-
- \ note that dlen from the source file class was redefined as a value in
- \ the source file struct
- : DataLength ( ^class -- n ) \ given a pointer to a class, return the
- \ length of the ivar data
- dlen&xwid drop ;
-
-
- \ define the non-trivial toolbox calls as normal words, not required, but
- \ this makes it easier to follow the methods, I think
-
- : PrValidate { thPrint -- b }
- word0 thPrint call PrValidate i->l ;
-
- : PrStlDialog { thPrint -- b }
- word0 thPrint call PrStlDialog i->l ;
-
- : PrJobDialog { thPrint -- b }
- word0 thPrint call PrJobDialog i->l ;
-
- : PrOpenDoc { thPrint tpPrPort tpIOBuf -- TPPrPort }
- 0 thPrint tpPrPort tpIOBuf call PrOpenDoc ;
-
- : PrError ( -- errorCode )
- word0 call PrError i->l ;
-
- \ now define some classes for the purpose of mapping into the Mac records
-
- :class TPrInfo super{ object }
- record
- { int iDev
- int iVRes \ vertical resolution of printer
- int iHRes \ horizontal resolution of printer
- rect rPage \ page rectangle
- }
- ;class
-
-
- :class TPrStl super{ object }
- record
- { int wDev \ high byte specifies device (1=ImageWriter, 3=LaserWriter)
- 6 bytes junk \ more fields for internal use, not mapped
- }
- ;class
-
-
- :class TPrJob super{ object }
- record
- { int iFstPage
- int iLstPage
- int iCopies
- byte bJDocLoop \ print method, 0=draft 1=spooled
- bool fFromUsr
- ptr pIdleProc \ background procedure
- ptr pFileName
- 4 bytes junk
- }
-
- :m spooled?: ( -- b)
- get: bJDocLoop 1 = ;m
-
- ;class
-
-
- :class THPrint super{ object }
- record
- { int iPrVersion
- TPrInfo prInfo
- rect rPaper
- TPrStl prStl
- TPrInfo prInfoPT
- 16 bytes prXInfo \ not mapped due to very limited use
- TPrJob prJob
- 38 bytes printX
- }
-
- :m spooled?: ( -- b)
- spooled?: prJob ;m
-
- ;class
-
-
- :class TPrStatus super{ object }
- record
- { int iTotPages \ number of pages in spool file
- int iCurPage \ page being printed
- int iTotCopies \ number of copies requested
- int iCurCopy \ copy being printed
- int iTotBands \ used internally
- int iCurBand \ used internally
- bool fPgDirty \ true if started printing page
- bool fImaging \ used internally
- handle hPrint \ print record
- var pPrPort \ printing grafport
- handle hPic \ used internally
- }
- ;class
-
-
- :class PrintManager super{ object }
-
- handle hPrint
- TPrStatus prStatus
- x-addr draw \ draw handler for printing
-
-
- :m put: ( cfa -- )
- put: draw ;m
-
- :m new: \ must call new: only once at runtime to allocate print record
- ['] THPrint DataLength new: hPrint ;m
-
- :m getnew: \ this method should obtain a print record from the resource
- \ fork of the file, if a file exists that is ( see PageSetup: comments
- \ and see IM II-150 Note: )
- \ This method is not implemented here, but would be used in place of new:.
- ;m
-
- :m release:
- release: hPrint ;m
-
- :m PageSetup: ( -- b) \ rundialog, returns 0 if user cancel
- \ if user did not cancel, it might be a good idea to save the hprint record
- \ to disk so the printing parameters chosen by the user can be restored.
- \ But this restoration is not automatic and must be done by the program.
- call PrOpen
- PrError 0=
- IF
- get: hPrint PrStlDialog
- THEN
- call PrClose ;m
-
- private
-
- \ note, only printing one page here ( so this isn't really a loop)
- :m printLoop: { \ pPrPort -- }
- get: hPrint 0 0 PrOpenDoc -> pPrPort
- PrError 0=
- IF
- pPrPort 0 call PrOpenPage \ pPageFrame=0, so no scaling
- PrError 0=
- IF
- exec: draw
- THEN
- pPrPort call PrClosePage
- THEN
- pPrPort call PrCloseDoc
-
- PrError 0=
- ptr: hPrint spooled?: THPrint and \ note message to class THPrint
- IF
- get: hPrint 0 0 0 addr: prStatus call PrPicFile
- THEN
- ;m
-
- public
-
- :m Print:
- call PrOpen
- PrError 0=
- IF
- pushport
-
- get: hPrint PrJobDialog
- IF printLoop: self THEN
-
- popport
- THEN
- call PrClose ;m
-
- ;class
-
- PrintManager pm \ instantiate an object, named pm, to do all printing work
-
- endload
-
-
-
-
- ********* Example usage of Print Manager **********
-
- : testPrint
- 30 30 80 80 put: temprect
- draw: temprect ;
-
- ' testPrint put: pm \ put the draw action in our PrintManager object
-
-
- new: pm \ must always call new: only once at runtime
-
- PageSetup: pm . \ not required, but does what it says
- Print: pm \ let er rip
-
- release: pm \ not required till quitting, i.e. can do multiple Print:'s
- \ without calling this. This just releases some memory.
-
-
-
- ****** Possible Enhancements ********
-
- Of course, we need to cycle through and print each requested page.
-
- I think a better printing model could be achieved by having a " print object"
- instance variable in the PrintManager class. It would simply be sent a
- print: message at the correct time, rather than sending exec: to an x-addr
- as is done here. I think it would be more flexible and robust to have the
- PrintManager object communicate with a print object.
-
- It would probably make sense to have printing be a function of the
- page rectangle and page number. So the print object would always
- be passed this information when a page is requested to be drawn.
- And probably the message should be PrintPage: with the rectangle and
- page number passed as parameters to the print object.
-
- Also, a way to easily save and restore the the page setup parameters in a
- file's resource fork would be nice. See suggested message getnew:.
-
- SInce no background procedure is provided, the toolbox will default to
- cancelling upon command-period. See IM II-152,153. But it shouldn't be
- difficult to provide a custom background procedure.
-
-
- ****** Comments *******
-
- Note the use of a class definition to map into a toolbox-created record,
- in this case the THPrint record. In the printLoop: method of class PrintManager
- we need to access a member of a record that is contained in a subrecord, in
- this case bjDocLoop (member of TPrJob, which is a subrecord of THPrint).
- Now we could have simply obtained the pointer to the print record, added
- the correct offset, and performed a c@:
-
- ptr: hPrint offset + c@
-
- But there are some problems with this approach, even though it may seem more
- straightforward. First, one must compute the offset. I have no idea what it
- is, nor do I wish to know. Second, one must remember to perform the correct
- type of "fetch" (c@ here, or was it c@x?). Thirdly, I don't think it is very
- clear what is going on here.
-
- Instead, I believe a better approach is to define the records as classes,
- define the required access methods, and then pass a message to a class with
- the appropriate base address on the stack:
-
- ptr: hPrint spooled?: THPrint
-
- Here the spooled?: message will be passed by class THPrint to its prJob ivar
- which will obtain the value of bjDocLoop contained in the record pointed to
- by ptr: hPrint.
-
- One must be careful when passing a message to a class that the address
- on the stack really does point to a data structure that matches the class.
- The offset (to bjDocLoop) is automatically computed, the appropriate "fetch"
- is automatically performed, and it is very clear what is going on. Also,
- one does not need to know the length of the THPrint record when allocating
- memory for the handle hPrint. Merely passing the class pointer to DataLength
- will do that job ( see definition of DataLength at the beginning of this file)
- as in the new: method for PrintManager.
-
-
-
- Doug Hoffman 24Jul92
-
- Compuserve 72310,1743